package dryven.util.json.dryvenjson;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import dryven.model.di.DependencyService;
import dryven.model.di.LocalThreadStorage;
import dryven.util.BeanUtil;

public class ExplicitGetterPolicy implements FieldPolicy {

	private BeanUtil beanUtil = new BeanUtil();
	private DependencyService _diService;
	
	public ExplicitGetterPolicy(DependencyService diService) {
		super();
		_diService = diService;
	}

	@Override
	public boolean includeField(Field f) {
		return f.getAnnotation(JSON.class)!=null;
	}

	@Override
	public boolean includeMethod(Method m) {
		return m.getAnnotation(JSON.class)!=null && 
			m.getReturnType()!=Void.TYPE;
	}

	@Override
	public Object getValueFromMethod(Method m, Object object, LocalThreadStorage diStorage) {
		if((m.getModifiers() & Modifier.PUBLIC)==0) {
			m.setAccessible(true);
		}
		try {
			return _diService.invokeMethod(diStorage, m, object, null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			if((m.getModifiers() & Modifier.PUBLIC)==0) {
				m.setAccessible(false);
			}	
		}
	}

	@Override
	public String getFieldName(Field f) {
		JSON json = f.getAnnotation(JSON.class);
		if(json.value().length()!=0) {
			return json.value();
		} else {
			return beanUtil.getPropertyName(f);
		}
	}

	@Override
	public String getFieldName(Method m) {
		JSON json = m.getAnnotation(JSON.class);
		if(json.value().length()!=0) {
			return json.value();
		} else {
			return beanUtil.getPropertyName(m);
		}
	}

	@Override
	public Object getValueFromField(Field f, Object object, LocalThreadStorage diStorage) {
		if((f.getModifiers() & Modifier.PUBLIC)==0) {
			f.setAccessible(true);
		}
		try {
			return f.get(object);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			if((f.getModifiers() & Modifier.PUBLIC)==0) {
				f.setAccessible(false);
			}	
		}
	}
}
